package org.zoomdev.zoom.web.action.impl;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zoomdev.zoom.common.config.ConfigReader;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.common.res.ResScanner;
import org.zoomdev.zoom.common.utils.CachedClasses;
import org.zoomdev.zoom.web.action.MethodAction;
import org.zoomdev.zoom.web.action.MethodActionHandler;
import org.zoomdev.zoom.web.annotations.Controller;
import org.zoomdev.zoom.web.annotations.Mapping;
import org.zoomdev.zoom.web.modules.CoreWebModule;
import org.zoomdev.zoom.web.router.Router;
import org.zoomdev.zoom.web.router.RouterParameterRule;

import java.lang.reflect.Method;
import java.util.List;

public final class MethodActionBuilder {

    private static final Logger log = LoggerFactory.getLogger(CoreWebModule.NAME);


    private final MethodAction action;
    private final ConfigReader configReader;
    private final ResScanner scanner;
    private final Router router;
    private final RouterParameterRule rule = new RouterParameterRule();
    private String scanFilter;

    public MethodActionBuilder(MethodAction action,
                               ConfigReader configReader,
                               ResScanner scanner,
                               Router router) {
        this.action = action;
        this.configReader = configReader;
        this.scanner = scanner;
        this.router = router;
    }

    public void setScanFilter(String scanFilter) {
        this.scanFilter = scanFilter;
    }

    public void build() {
        String pattern = this.scanFilter;// configReader.getString("zoom.scan.controllers");
        if (StringUtils.isEmpty(pattern)) {
            pattern = "*.controllers.*";
        }

        List<ResScanner.ClassRes> classRes = scanner.findClass(pattern);
        for (ResScanner.ClassRes res : classRes) {
            Class<?> controllerType = res.getType();
            buildSingle(controllerType);
        }
    }

    public void buildSingle(Class<?> controllerType) {
        Controller controller = controllerType.getAnnotation(Controller.class);
        if (controller == null) {
            return;
        }
        /**
         * 基本形式为  key + /  + method.getName()
         */
        for (Method method : CachedClasses.getPublicMethods(controllerType)) {
            Mapping mapping = method.getAnnotation(Mapping.class);
            String[] methods = mapping != null ? mapping.method() : null;
            String fullKey = getKey(controller.key(), method, mapping);
            //路径参数
            String[] pathVariableNames = rule.getParameterNames(fullKey);
            if (CoreWebModule.showControllerLogs) {
                log.info("Controller:" + fullKey + "===>" + method);
            }
            //这个路径 支持 这么多http方法映射到这个method上面执行
            try {

                MethodActionHandler config = new MethodActionHandler(fullKey,
                        methods,
                        pathVariableNames,
                        action,
                        controllerType,
                        method);
                router.add(config);
            } catch (Exception e) {
                log.info("映射Controller出错" + method, e);
                if (e instanceof RuntimeException)
                    throw (RuntimeException) e;
                throw new ZoomException(e);
            }
        }
    }

    private static String getKey(String key, Method method, Mapping mapping) {
        if (mapping != null && !StringUtils.isEmpty(mapping.value())) {
            if (!mapping.value().startsWith("/")
                    && !key.endsWith("/") && !mapping.value().isEmpty()) {
                key += "/" + mapping.value();

            } else {
                key += mapping.value();
            }

        } else {
            if (!key.endsWith("/")) {
                key += "/" + method.getName();
            } else {
                key += method.getName();
            }
        }
        if (!key.startsWith("/")) {
            key = "/" + key;
        }
        return key;
    }

}
